package com.yazi.mxz.mobile.common;

import java.util.List;

import javax.annotation.Resource;

import com.myframework.smhj.common.exception.MyException;
import com.myframework.smhj.common.tool.DateUtil;
import com.myframework.smhj.jackson.result.ObjectResult;
import com.myframework.smhj.jackson.result.StatusResult;
import com.yazi.mxz.common.MyUtil;
import com.yazi.mxz.common.entity.beans.Member;
import com.yazi.mxz.common.entity.beans.SecurityQuestion;
import com.yazi.mxz.common.service.MemberService;
import com.yazi.mxz.common.service.SecurityQuestionService;
import com.yazi.mxz.mobile.common.VerifyAbstractController;
import com.yazi.mxz.mobile.jackson.filter.MemberFilter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 找回密码
 * @author mo_yq5
 * @date 2015-9-20
 */
public class ForgetPwdAbstractController extends VerifyAbstractController {
	private static Logger log = LoggerFactory.getLogger(ForgetPwdAbstractController.class);
	/**
	 * 要找回密码的账户（用户）的Session key
	 */
	private static final String SESSION_KEY_FORGET_MEMBER = "forgetPwd_forgetMember";
	/**
	 * 已经验证通过的要找回密码的账户（用户）的Session key
	 */
	private static final String SESSION_KEY_VERIFIED_MEMBER = "forgetPwd_verifiedMember";
	
	@Resource
	MemberService memberService;
	@Resource
	SecurityQuestionService securityQuestionService;
	
	/**
	 * 记住要找回密码的账户（用户）
	 * @param account 账户名
	 * @param captcha 网页验证码
	 * @return
	 */
	@RequestMapping("/checkNameDo/json")
	@ResponseBody
	public ObjectResult<?> checkNameDoJson(String account, String captcha) {
		log.debug("验证账户名");
		ObjectResult<Member> jsonResult = new ObjectResult<Member>();
		jsonResult.setFilter(MemberFilter.get4ForgetPwd());
		try {
			if (!checkCaptcha(captcha)) {
				jsonResult.setFailMessage("验证码不正确");
				return jsonResult;
			}
			Member member = memberService.oneByAccountName(account);
			if (null == member) {
				jsonResult.setFailMessage("账户不存在");
				return jsonResult;
			}
			
			// 记住
			setFogetMember(member);
						
			String email;
			if (null != (email = member.getEmail())) {
				String r = email.substring(3, email.indexOf("@")).replaceAll("[\\S]", "*");
				email = email.substring(0, 3) + r + email.substring(email.indexOf("@"), email.length());
				member.setEmail(email);
			}
			String mobile;
			if (null != (mobile = member.getMobile())) {
				member.setMobile(mobile.substring(0, 3) + "****" + mobile.substring(7, 11));
			}
						
			jsonResult.setResult(member);
			jsonResult.setOk();
		} catch (Exception e) {
			log.debug("账户名验证异常", e);
			jsonResult.setErrorMessage("操作失败，请联系管理员");
		}
		return jsonResult;
	}
	
	/**
	 * 发邮件/手机验证码
	 * @return
	 */
	@RequestMapping("/sendDo/json")
	@ResponseBody
	public ObjectResult<?> sendDoJson(VerifyType type) {
		ObjectResult<Long> jsonResult = new ObjectResult<Long>();
		Member member;
		try {
			member = getFogetMember();
			if (null == member) {
				jsonResult.setFailMessage("操作超时");
				return jsonResult;
			}
			if (type == VerifyType.EMAIL) {
				setCaptchaForEmail(member.getName(), member.getEmail());
				jsonResult.setResult(getEmailLag());
			} else if (type == VerifyType.MOBILE) {
				setCaptchaForMobile(member.getMobile());
				jsonResult.setResult(getSmsLag());				
			}
			jsonResult.setOk();
		} catch (MyException e) {
			log.debug("发送验证码失败：", e);
			jsonResult.setFailMessage(e.getMessage());
		} catch (Exception e) {
			log.error("发送验证码异常：", e);
			jsonResult.setErrorMessage("操作失败，请联系管理员");
		}
		return jsonResult;
	}
	
	/**
	 * 手机/邮箱/安全问题验证
	 * @param type
	 * @param captcha
	 * @param answer4Form
	 * @return
	 */
	@RequestMapping("/verifyDo/json")
	@ResponseBody
	public StatusResult verifyDoJson(VerifyType type, String captcha, Answer4Form answer4Form) {
		StatusResult jsonResult = new StatusResult();
		try {
			Member member = getFogetMember();
			if (null == member) {
				jsonResult.setFailMessage("操作超时");
				return jsonResult;
			}
			if (!verify(type, captcha, answer4Form.getSqList())) {
				jsonResult.setFailMessage("验证错误");
				return jsonResult;
			}
			// 记住
			setVerifiedMember(member);
			jsonResult.setOk();
		} catch (Exception e) {
			log.error("验证异常:", e);
			jsonResult.setErrorMessage("操作失败，请联系管理员");
		}
		return jsonResult;
	}
	
	@RequestMapping("/pwdDo/json")
	@ResponseBody
	public StatusResult pwdDoJson(String pwd) {
		log.debug("修改密码");
		StatusResult jsonResult = new StatusResult();
		try {
			Member member = getVerifiedMember();
			if (null == member) {
				jsonResult.setFailMessage("操作超时");
				return jsonResult;
			}
			member = memberService.one(member.getMemberId());
			member.setPassword(pwd);
			MyUtil.encodePwd(member);
			memberService.merge(member);
			setFogetMember(null);
			setVerifiedMember(null);
			jsonResult.setOk();
		} catch (Exception e) {
			log.error("修改密码异常：", e);
			jsonResult.setErrorMessage("操作失败，请联系管理员");
		}
		return jsonResult;
	}
	
	/**
	 * 清除已经记住的账户（用户）
	 */
	public void resetForgetMember() {
		setFogetMember(null);
		setVerifiedMember(null);
	}
	
	/**
	 * 记住当前要找回密码的账户(用户)
	 * @param member
	 */
	private void setFogetMember(Member member) {
		if (null == member) {
			getSession().removeAttribute(SESSION_KEY_FORGET_MEMBER);
			return;
		}
		
		log.debug("用户找回密码：name={}", member.getName());
		
		FogetMember fm = new FogetMember();
		fm.setMemberId(member.getMemberId());
		getSession().setAttribute(SESSION_KEY_FORGET_MEMBER, fm);
		
	}
	
	/**
	 * 获取已经记住的要找回密码的账户(用户)
	 * @return
	 */
	private Member getFogetMember() {
		FogetMember fm = (FogetMember)getSession().getAttribute(SESSION_KEY_FORGET_MEMBER);
		// TODO 指定的忘记密码账户10内分钟有效(即有效时间内完成身份难,否则重置找密码流程)
		if (null == fm || fm.getTimestamp() < DateUtil.getTimeStamp() - 6e5 ) {
			return null;
		}
		return memberService.one(fm.getMemberId());
	}
	
	/**
	 * 记住已经通过验证的要找回密码的账户(用户)
	 * @param member
	 */
	private void setVerifiedMember(Member member) {
		if (null == member) {
			getSession().removeAttribute(SESSION_KEY_VERIFIED_MEMBER);
			return;
		}
		
		log.debug("用户找回密码验证通过：name={}", member.getName());
		
		FogetMember fm = new FogetMember();
		fm.setMemberId(member.getMemberId());
		getSession().setAttribute(SESSION_KEY_VERIFIED_MEMBER, fm);
		
	}
	
	/**
	 * 获取已经通过验证的要找回密码的账户(用户)
	 * @return
	 */
	private Member getVerifiedMember() {
		FogetMember fm = (FogetMember)getSession().getAttribute(SESSION_KEY_VERIFIED_MEMBER);
		// TODO 验证通过的账户10内分钟有效(即有效时间内重设密码,否则需要重新验证)
		if (null == fm || fm.getTimestamp() < DateUtil.getTimeStamp() - 6e5 ) {
			return null;
		}
		return memberService.one(fm.getMemberId());
	}
	
	/**
	 * 安全问题验证<br>
	 * 需要用户所有的问题回答正确才能返回true，否则false。
	 * @param questionList
	 * 			账户(用户)的所有问题
	 * @param answerList
	 * 			用户回答的问题
	 * @return
	 */
	private boolean checkQuestionAnswer(List<SecurityQuestion> questionList, List<SecurityQuestion> answerList) {
		String answer;
		boolean oneFalse = false;
		// 需要用户所有的问题回答正确
		for (SecurityQuestion destSq : questionList) {
			oneFalse = true;
			for (SecurityQuestion sq : answerList) {
				answer = MyUtil.encodeSecurityAnswer(sq.getAnswer());
				if (destSq.getQuestionId().equals(sq.getQuestionId()) 
						&& destSq.getAnswer().equals(answer)) {
					oneFalse = false;
				}
			}
			if (oneFalse) {
				return false;
			}
		}
		
		return true;
	}
	
	/**
	 * 手机/邮件/安全问题。。。进行验证的共同方法
	 * @param type 验证类型
	 * @param captcha 验证码
	 * @param answerList  安全问题（答案）
	 * @return
	 */
	private boolean verify(VerifyType type, String captcha, List<SecurityQuestion> answerList) {
		Member member = getFogetMember();
		boolean verified = false;
		switch(type) {
		case EMAIL:
			verified = checkEmailCaptcha(member.getEmail(), captcha);
			break;
		case MOBILE:
			verified = checkSmsCaptcha(member.getMobile(), captcha);
			break;
		case QUESTION:
			// sq for search
			SecurityQuestion sq4s = new SecurityQuestion();
			sq4s.setMember(member);
			// 用户所有问题
			List<SecurityQuestion> questionList = securityQuestionService.list(sq4s);
			verified = checkQuestionAnswer(questionList, answerList);
			break;
		}
		
		return verified;
	}
	
	
	public enum VerifyType {
		MOBILE, EMAIL, QUESTION;
	}
	
	public static class Answer4Form {
		private List<SecurityQuestion> sqList;

		public List<SecurityQuestion> getSqList() {
			return sqList;
		}

		public void setSqList(List<SecurityQuestion> sqList) {
			this.sqList = sqList;
		}
	}
	
	class FogetMember {
		// 要找回的用户ID
		private long memberId;
		// 开始操作的时间
		private long timestamp = DateUtil.getTimeStamp();
		
		public long getTimestamp() {
			return timestamp;
		}
		public void setTimestamp(long timestamp) {
			this.timestamp = timestamp;
		}
		public long getMemberId() {
			return memberId;
		}
		public void setMemberId(long memberId) {
			this.memberId = memberId;
		}
	}
	
}
